﻿package PinballCode.Screens
{
	import flash.display.Stage;
	import PinballCode.MainApp;
	import PinballCode.*;
	import flash.events.MouseEvent;
	import flash.events.Event;
	import com.as3toolkit.events.KeyboarderEvent;
	import com.as3toolkit.ui.Keyboarder;
	import flash.ui.Keyboard;
	import flash.utils.*;
	
	// Game Screen which has the hud and Board with it
	public class Game extends Screen
	{
		//Attributes
		var plunger:Plunger;			// plunger object
		var ball:Ball;					// ball object
		var leftFlip:Bar;			// left flipper object
		var rightFlip:Bar;			// right flipper object
		
		// Game times
		public var oldTime:int;           		 // previous system time (for animation)
		public var newTime:int;           	 	// current system time (for animation)
		public var dt:Number;              		// change in system time (also for animation)
		public var isActive:Boolean;       		// disable/enable user input for game
		private var spaceHeld:Boolean;			// boolean if space was held recently
		private var spaceJustReleased:Boolean;	// varible that tells if space was just released
		private var scaleTime:int;                  //timer used to stop the kicker from scaling forever
		private var pauseTime:int;                  //also used for scaling
		
		private var listOfObjects:Array;		// list of objs
		
		var xmlObject:XML;						// used so that flash doesn't give us warnings about "MULTIPLE COPIES":
		
		
		private var mouseDown:Boolean;			// varible used with ball being held
		
		
		// Game Screen constructor
		public function Game(app:MainApp)
		{
			super(app);		
			init();
		}
		
		// initiaizes the game screen
		public function init():void {
			listOfObjects = new Array();
			setUpTable();
		}
		
		// Resets the game when the screen is accessed
		public function reset():void {
			QuitButton_mc.addEventListener(MouseEvent.CLICK, quitGame);
			PauseButton_mc.addEventListener(MouseEvent.CLICK, pauseGame);
			this.isActive = false; 
			spaceHeld = false;
			playGame();  // start game loop
			debug();
			hud_mc.init();
			ballReset();
		}
		
		// Resets the ball to be on the plunger
		public function ballReset():void {
			ball.x = plunger.x + plunger.width/2;
			ball.y = plunger.y - plunger.height - ball.height/2;
			ball.reset();
		}
		
		// Adds the function of Ball being picked up
		public function debug():void {
			mouseDown = false;
			addEventListener(MouseEvent.MOUSE_UP, Drop);
			ball.addEventListener(MouseEvent.MOUSE_DOWN, Drag);
		}
		
		// Drags Ball
		private function Drag(event:MouseEvent):void
		{
			// checks if game isnt paused and makes sure it is allowed to move the node
				if(event.target is Ball){
					event.target.startDrag();
					ball.still();
				}
				mouseDown = true;			
		}
		
		// stops Ball from being dragged
		private function Drop(event:MouseEvent):void
		{ 
			stopDrag();
			if(event.target is Ball)
			mouseDown = false;
		}
		
		// Sets up the Table
		public function setUpTable():void {
			setUpBumpers();
			setUpFlippers();
			setUpWalls();
			setUpTriangles();
			setUpKickers();
			setUpSpinners();
			setUpPlunger();
			setUpBall();
		}
		
		
		//Sets up the Bumpers
		private function setUpBumpers():void {
			var tempBumper:Bumper;					// temp var to be used
			var wall;
			var xpos;
			var ypos;
			for each(xmlObject in app.xmlData.GameObjects.Bumpers.bumber)
			{
				xpos = xmlObject.@xPos;
				ypos = xmlObject.@yPos;
				tempBumper = new Bumper(xmlObject.@sides,xmlObject.@radius,new Vertex(xpos,ypos),xmlObject.@score,xmlObject.@thickness,xmlObject.@color);
				board_mc.addChild(tempBumper);
				listOfObjects.push(tempBumper);
				for each(wall in tempBumper.walls)
				{
					board_mc.addChild(wall);
				}
			}
		}
		
		//Sets up the flippers
		private function setUpFlippers():void {
			var flip:Bar;					// temp var to be used
			var lft:Boolean = true;				// bool for left or right flipper
			for each(xmlObject in app.xmlData.GameObjects.Flippers.flipper)
			{
				flip = new Bar(new Vertex(xmlObject.@pos1X,xmlObject.@pos1Y),new Vertex(xmlObject.@pos2X,xmlObject.@pos2Y),lft);
				board_mc.addChild(flip);
				if(lft)
				leftFlip = flip;
				else
				rightFlip = flip;
				
				lft = false;
			}
			
		}
		
		//Sets up the walls
		private function setUpWalls():void {
			var wall:Wall;							// temp var to be used
			for each(xmlObject in app.xmlData.GameObjects.Walls.wall)
			{
				wall = new Wall(new Vertex(xmlObject.@pos1X,xmlObject.@pos1Y),new Vertex(xmlObject.@pos2X,xmlObject.@pos2Y));
				board_mc.addChild(wall);
				listOfObjects.push(wall);
			}
			
		}
		
		//Sets up the triangles
		private function setUpTriangles():void {
			var tri:Triangle;		// temp var to be used
			var wall:Wall;			
			var left:Boolean = true;
			
			for each(xmlObject in app.xmlData.GameObjects.Triangles.triangle)
			{
				
				tri = new Triangle(new Vertex(xmlObject.@pos1X,xmlObject.@pos1Y),new Vertex(xmlObject.@pos2X,xmlObject.@pos2Y),new Vertex(xmlObject.@pos3X,xmlObject.@pos3Y),left);
				board_mc.addChild(tri);
				listOfObjects.push(tri);
				left = !left;
				for each(wall in  tri.walls)
				{
					board_mc.addChild(wall);
				}
			}
			
		}
		
		//Sets up the Kickers (Trapezoids essentially, but give points for being hit on one particular side)
		private function setUpKickers():void
		{	
			var wall;
			var myKicker:Kicker;					// to be added for each item in the XML file's kicker section
			for each(xmlObject in app.xmlData.GameObjects.Kickers.Kicker)
			{
				myKicker = new Kicker(new Vertex(xmlObject.@centerX, xmlObject.@centerY), xmlObject.@rad1, xmlObject.@rad2, xmlObject.@lineThickness, xmlObject.@color1, xmlObject.@color2);
				board_mc.addChild(myKicker);
				listOfObjects.push(myKicker);
				for each(wall in  myKicker.walls)
				{
					board_mc.addChild(wall);
				}
			}
		}
		
		//Sets up the Spinners (big Xs)
		private function setUpSpinners():void
		{
			var wall;
			/*var mySpinner = new Spinner(new Vertex(40, 40), 15, 50);
			board_mc.addChild(mySpinner);
			listOfObjects.push(mySpinner);*/
			trace("spinner attempted to be drawn");
			var mySpinner:Spinner;					// to be added for each item in the XML file's kicker section
			for each(xmlObject in app.xmlData.GameObjects.Spinners.spinner)
			{
				trace("spinner found");
				mySpinner = new Spinner(new Vertex(xmlObject.@centerX, xmlObject.@centerY), xmlObject.@rad1, xmlObject.@rad2, xmlObject.@color1, xmlObject.@color2);
				board_mc.addChild(mySpinner);
				listOfObjects.push(mySpinner);
				trace("spinner drawn");
				for each(wall in  mySpinner.walls)
				{
					board_mc.addChild(wall);
				}
			}
		}
		
		//Sets up the Plunger
		private function setUpPlunger():void {
			for each(xmlObject in app.xmlData.GameObjects.plunger)
			{
				plunger = new Plunger(xmlObject.@height,xmlObject.@width);
				board_mc.addChild(plunger);
				plunger.x = xmlObject.@xPos;
				plunger.y = xmlObject.@yPos;
			}
			
		}
		
		//Sets up the Ball
		private function setUpBall():void {
			for each (xmlObject in app.xmlData.GameObjects.ball) {
				trace(xmlObject);
				ball = new Ball(xmlObject.@radius, xmlObject.@color, xmlObject.@thickness, xmlObject.@maxV, xmlObject.@mass, xmlObject.@gravity, xmlObject.@friction);
				board_mc.addChild(ball);
				ball.x = plunger.x + plunger.width/2;
				ball.y = plunger.y - plunger.height - ball.height/2;			
			}
		}
		
		// quit the game and transition to a new screen
		public function quitGame(e:MouseEvent)
		{
			exitScreen();
			
			app.displayScreen(MainMenu);
			//other game-ending related code
		}
		
		// Removes the listeners and exit the game
		public function exitScreen():void {
			removeEventListener(Event.ENTER_FRAME, doEnterFrame);
			this.isActive = false; 
			QuitButton_mc.removeEventListener(MouseEvent.CLICK, quitGame);
			
			removeEventListener(MouseEvent.MOUSE_UP, Drop);
			ball.removeEventListener(MouseEvent.MOUSE_DOWN, Drag);
			
			PauseButton_mc.removeEventListener(MouseEvent.CLICK, pauseGame);
			PauseButton_mc.removeEventListener(MouseEvent.CLICK, unPauseGame);
		}
		
		// Allows the game to be paused
		public function pauseGame(e:MouseEvent)
		{
			this.isActive = false; 
			removeEventListener(Event.ENTER_FRAME, doEnterFrame);
			
			PauseButton_mc.removeEventListener(MouseEvent.CLICK, pauseGame);
			
			PauseButton_mc.addEventListener(MouseEvent.CLICK, unPauseGame);
			
			removeEventListener(MouseEvent.MOUSE_UP, Drop);
			ball.removeEventListener(MouseEvent.MOUSE_DOWN, Drag);
		}
		
		// Play the game when paused
		public function unPauseGame(e:MouseEvent)
		{
			addEventListener(Event.ENTER_FRAME, doEnterFrame);
			
			PauseButton_mc.removeEventListener(MouseEvent.CLICK, unPauseGame);
			
			PauseButton_mc.addEventListener(MouseEvent.CLICK, pauseGame);
			
			addEventListener(MouseEvent.MOUSE_UP, Drop);
			ball.addEventListener(MouseEvent.MOUSE_DOWN, Drag);
		}
		
		// Play the game and start game loop
		public function playGame():void {
			addEventListener(Event.ENTER_FRAME, doEnterFrame);
			
		}
		
		//-----------------------------------------------------------------------------------------------
		// Game loop
		//-----------------------------------------------------------------------------------------------
		public function doEnterFrame(anEvent:Event):void
		{
			if (isActive) {
				updateTime();
				checkInput();
				moveBall();
				checkCollide();
				oldTime = newTime;
			} 
			else { 
				isActive = true; 
				oldTime = getTimer(); // reset prev system time increment
			}
		}
		
		// Evaluate dt for each loop:
		public function updateTime():void {
			newTime = getTimer();
			dt = (newTime-oldTime)/1000; // "fudge factor" of 1000 to smooth out the animation
		}
		
		// Checks input of keyboard
		public function checkInput():void {
			//Move Left Flippers
			if (Keyboarder.keyIsDown(Keyboard.Z) || Keyboarder.keyIsDown(Keyboard.LEFT))
			{
				leftFlip.changeAcc(true);
			}
			else 
				leftFlip.changeAcc(false);
				
			//Move Right Flippers
			if (Keyboarder.keyIsDown(Keyboard.X) || Keyboarder.keyIsDown(Keyboard.RIGHT)) 
			{
				rightFlip.changeAcc(true);
			}
			else 
				rightFlip.changeAcc(false);
			leftFlip.updateBar(dt);
			rightFlip.updateBar(dt);
			// Move Plunger
			if (Keyboarder.keyIsDown(Keyboard.SPACE))
			{
				spaceHeld = true;
				spaceJustReleased = false;
				plunger.hold(dt);
			}
			else
			{
				if(spaceHeld)
				{
					spaceHeld = false;
					spaceJustReleased = true;
				}
				else
				{
					plunger.reset(dt);
					spaceJustReleased = false;
				}
			}
		}
		
		// Move ball 
		public function moveBall():void {
			if(!mouseDown){
		
			if(!ball.onPlunger)
			{
				ball.x += ball.MoveX(dt*10);
				ball.y += ball.MoveY(dt*10);
			}
			}
		}
		
		// Check if collide and update:
		public function checkCollide():void {
			
			if(ball.y > stage.stageHeight)
			{
				if(hud_mc.Balls > 0)
				{
					hud_mc.loseBall();
					ballReset();
				}
				else
				{
					GameOver();
				}
			} else
			
			
			// Ball hits the Plunger
			if (ball.hitTestObject(plunger))
			{
				if(spaceHeld) {
					ball.still();
				}
				else
				{
					if(spaceJustReleased) {
						ball.vy =(plunger.release());
						//trace("LLLLLLLLL" + plunger.release());
						//trace(ball.vy);
						ball.onPlunger = false;
					}
						
					else if(!ball.onPlunger && ball.vy > 0) {
						trace("bounces");
						ball.bounces(0);
					}
						
				}
				ball.y = plunger.y - plunger.height - ball.height/2;
			}
			else
			{
				ball.onPlunger = false;
			}
			
			if(ball.hitTestObject(leftFlip))
			{
				ball.checkLine(leftFlip,dt,true);
			}
			if(ball.hitTestObject(rightFlip))
			{
				ball.checkLine(rightFlip,dt,true);
			}
			
			// Loop through all objects
			for(var i:int = 0; i < listOfObjects.length; i++)
			{                 
				if(listOfObjects[i] is Bumper)
				{
					listOfObjects[i].animate(dt*10);
					// Ball hits Bumper  
					
					if(ball.hitTestObject(listOfObjects[i])) {
						  for(var o:int=0; o < listOfObjects[i].walls.length; o++)
						  {
							  
								if(ball.checkLine(listOfObjects[i].walls[o],dt))
								{								
									listOfObjects[i].collision();							  
									 hud_mc.changeScore(listOfObjects[i].Score);
									
								}
						  }
					   }
				}
				
				if(listOfObjects[i] is Triangle)
				{
					// Ball hits Triangle
					if(ball.hitTestObject(listOfObjects[i]))
					  {
						  for(o=0; o < listOfObjects[i].walls.length; o++)
						  {
							  
								if(ball.checkLine(listOfObjects[i].walls[o],dt))
								{														  
									 hud_mc.changeScore(10);
									
								}
						  }
					  }
				}
				if(listOfObjects[i] is Kicker)
				{
					// Ball hits Kicker
					if(ball.hitTestObject(listOfObjects[i]))
					  {
//<<<<<<< .mine
						 for(var o:int=0; o < listOfObjects[i].walls.length; o++)
						  {
							  
								if(ball.checkLine(listOfObjects[i].walls[o],dt))
								{										  
									 hud_mc.changeScore(10);
									
								}
						  }
//=======
					
						  scaleTime = getTimer();
						  
						  //for the ball to get 'kicked' specially and get points, it must be within the max and min Y.
						  if ((scaleTime-pauseTime >= 300) && ball.y < listOfObjects[i].getMax() && ball.y > listOfObjects[i].getMin())
						  {
						  	hud_mc.changeScore(10);
							listOfObjects[i].scale(1.1, 1.1);
							pauseTime = getTimer();
							//reverse ball direction!
						  }
						  
						  else if (scaleTime -pauseTime >= 300)
						  {
							  listOfObjects[i].scale((1/1.1), (1/1.1)); //scale back
						  }
//>>>>>>> .r28
					  }
				}
				if(listOfObjects[i] is Spinner)
				{
					// Ball hits Spinner
					if(ball.hitTestObject(listOfObjects[i]))
					  {
						  for(var o:int=0; o < listOfObjects[i].walls.length; o++)
						  {
							  
								if(ball.checkLine(listOfObjects[i].walls[o],dt))
								{														  
									 hud_mc.changeScore(10);
									
								}
						  }
					  }
				}

				if(listOfObjects[i] is Wall)
				{
					// Ball hits Wall
					if(ball.hitTestObject(listOfObjects[i]))
					  {
						  ball.checkLine(listOfObjects[i],dt);
					  }
				}
			}
			
			//update the balls and score
			hud_mc.updateHUD();
		}
		
		// When the balls run out
		public function GameOver():void {
			exitScreen();
			app.displayScreen(CreditScreen);
		}
		
		
		
	}
}